package crawler

import (
	"gitee.com/gcom/stockdock/core/support"
	"golang.org/x/net/publicsuffix"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"
	"sync"
	"time"
)

var cookieJar, _ = cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})

type entry struct {
	cookies []*http.Cookie
	ts      time.Time
}

var cookieLock sync.Mutex
var cookieMap = make(map[string]*entry)

func GetCookieString(ctx support.TracerCtx, requestUrl, reloadUrl string, keys []string) string {
	cookies := GetCookies(ctx, requestUrl, reloadUrl)
	var arr = make([]string, 0, len(keys))
	var keyset = make(map[string]bool, len(keys))
	for _, k := range keys {
		keyset[k] = true
	}
	for _, c := range cookies {
		if _, ok := keyset[c.Name]; ok {
			arr = append(arr, c.Name+"="+c.Value)
		}
	}
	return strings.Join(arr, "; ")
}

func GetCookies(ctx support.TracerCtx, requestUrl, reloadUrl string) []*http.Cookie {
	u1, err := url.ParseRequestURI(requestUrl)
	if err != nil {
		ctx.Logger.Errorf("无效的URL: %s, %v", requestUrl, err)
		return nil
	}

	if en := cookieMap[u1.Host]; en != nil && time.Now().Sub(en.ts) < 10*time.Minute {
		return filterCookies(u1.Host, en.cookies)
	}

	u2, e := url.ParseRequestURI(reloadUrl)
	if e != nil {
		ctx.Logger.Errorf("无效的URL: %s, %v", requestUrl, e)
		return nil
	}
	cookies, _ := reloadCookie(ctx, u2, u1.Host)
	return filterCookies(u1.Host, cookies)
}

func reloadCookie(ctx support.TracerCtx, u *url.URL, domain string) ([]*http.Cookie, error) {
	ccookies, err := LoadAndResolveCookie(ctx, u, 10, nil)
	if err != nil {
		ctx.Logger.Errorf("获取cookie失败, %v", err)
		return nil, err
	}

	cookieLock.Lock()
	defer cookieLock.Unlock()
	en := &entry{
		ts: time.Now(),
	}
	cookies := make([]*http.Cookie, len(ccookies))
	for i, v := range ccookies {
		cookies[i] = &http.Cookie{
			Name:    v.Name,
			Value:   v.Value,
			Path:    v.Path,
			Domain:  v.Domain,
			Expires: time.Unix(0, int64(v.Expires)*int64(time.Second)),
		}
	}
	en.cookies = cookies
	cookieMap[domain] = en
	return cookies, nil
}

func filterCookies(domain string, cookies []*http.Cookie) []*http.Cookie {
	var result []*http.Cookie
	for _, v := range cookies {
		if v.Domain == domain || (len(v.Domain) < len(domain) &&
			v.Domain[0] == '.' && domain[len(domain)-len(v.Domain):] == v.Domain) {
			result = append(result, v)
		}
	}
	return result
}
